using System;
using System.Collections;
using Curriculum.Metadatos.ClasesMetadatos;
using Curriculum.Modelo.Clases;
using Curriculum.Modelo.Enum;
using Curriculum.Utiles;
using Db4objects.Db4o.Query;

namespace Curriculum.DataAccess.Predicates
{
	#region Clases Predicates

	#region Metadatos

	public class GetAntecedentesMetadatoHuerfanosPredicate : Predicate
	{
		public GetAntecedentesMetadatoHuerfanosPredicate()
		{}

		public bool Match(AntecedenteMetadato antMeta)
		{
			return ((antMeta.IdPadre == null) || (antMeta.Equals("0")));
		}
	}

	public class GetNodosMetadatoHijosPredicate : Predicate
	{
		string _idPadre;

		public GetNodosMetadatoHijosPredicate(string idPadre)
		{	
			_idPadre = idPadre;
		}

		public bool Match(AntecedenteMetadato antecedenteMetadato)
		{
			return (antecedenteMetadato.IdPadre.Equals(this._idPadre));
		}
	}

	public class GetVersionMetadatoByNroVersionPredicate : Predicate
	{
		public GetVersionMetadatoByNroVersionPredicate()
		{
		}

		public bool Match(VersionMetadato versionMetadato)
		{
			return true;
		}
	}

	public class GetAtributoMetadatoByIdPredicate : Predicate
	{
		private string _id;

		public GetAtributoMetadatoByIdPredicate(string id)
		{
			_id = id;
		}

		public bool Match(AtributoMetadato atributoMetadato)
		{
			return (atributoMetadato.Id.Equals(_id));
		}
	}

	public class AntecedentesMetadatoByIdPredicate : Predicate
	{
		string _id;

		public AntecedentesMetadatoByIdPredicate(string id)
		{
			_id = id;
		}

		public bool Match(AntecedenteMetadato antMeta)
		{
			return antMeta.Id.Equals(_id);
		}
	}


	public class AntecedenteMetadatoConAtributosTipoListaPredicate : Predicate
	{
		public AntecedenteMetadatoConAtributosTipoListaPredicate()
		{}

		public bool Match(AntecedenteMetadato anteMeta)
		{
			if (anteMeta.AtributoMetadatos != null)
			{
				foreach (AtributoMetadato atributoMeta in anteMeta.AtributoMetadatos)
				{
					if (atributoMeta.IdTipoDato.Equals(Constants.ID_ATRIBUTOS_TIPO_LISTA))
					{
						return true;
					}
				}
			}

			return false;
		}
	}
	#endregion

	#region Docente

	public class DocenteLikePredicate : LikePropertyPredicate
	{
		public DocenteLikePredicate(string nombreDocente, string apellidoDocente, string cuil)
			: base(new Hashtable(3), new Hashtable())
		{
			this._likeProperties["Nombre"] = nombreDocente;
			this._likeProperties["Apellido"] = apellidoDocente;
			this._likeProperties["Cuil"] = cuil;
		}
	
		public bool Match(Docente doc)
		{
			return base.Match(doc);
		}
	}

	#endregion

	#region Rol

	public class RolPredicate : Predicate
	{
		private string _nombreRol;
		private string _rolId;
		public RolPredicate(string nombreRol, string rolId)
		{
			_nombreRol = nombreRol;
			_rolId = rolId;
		}

		public bool Match(Rol rol)
		{
			return (rol.GetType().Name.Equals(_nombreRol) && ConicideIdRol(rol.Id));
		}

		public bool ConicideIdRol(string idRol)
		{
			return (_rolId.Equals(string.Empty) || _rolId.Equals(idRol));
		}
	}

	#endregion

	#region Usuario

	public class GetUsuarioPorNombrePredicate : Predicate
	{
		string _nombre;

		public GetUsuarioPorNombrePredicate(string nombre)
		{
			_nombre = nombre;
		}

		public bool Match(Usuario usuario)
		{
			return (usuario.Username.Equals(_nombre));
		}
	}

	public class UsuarioPorRolPredicate : Predicate
	{
		private string _nombreRol;
		private string _idRol;

		public UsuarioPorRolPredicate(string nombreRol, string idRol)
		{
			_nombreRol = nombreRol;
			_idRol = idRol;
		}

		public bool Match(Usuario usuario)
		{
			return usuario.Rol.GetType().Name.Equals(_nombreRol) && usuario.Rol.Id.Equals(_idRol);
		}

	}

	public class UsuarioPorNombreYRolPredicate : Predicate
	{
		private string _tipoRol;
		private string _userName;

		public UsuarioPorNombreYRolPredicate(string rol, string userName)
		{
			_tipoRol = rol;
			_userName = userName.ToLower();
		}

		public bool Match(Usuario usuario)
		{
			return (usuario.Username.ToLower().Equals(_userName) 
				&&usuario.Rol.GetType().Name.Equals(_tipoRol) );

		}		
	}

	public class UsuarioPredicate : Predicate
	{
		private string _tipoRol;
		private string _userName;
		private string _password;

		public UsuarioPredicate(string rol, string userName, string password)
		{
			_tipoRol = rol;
			_userName = userName.ToLower();
			_password = password.ToLower();
		}

		public bool Match(Usuario usuario)
		{
			return (usuario.Username.ToLower().Equals(_userName) 
					&& usuario.Password.ToLower().Equals(_password)
					&&usuario.Rol.GetType().Name.Equals(_tipoRol) );

		}		

	}


	public class UsuarioLikePredicate : LikePropertyPredicate
	{		
		private string _tipoRol;

		public UsuarioLikePredicate(string apellido, string nombre, string tipoRol, string username)
			: base(new Hashtable(3), new Hashtable())
		{
			_tipoRol = tipoRol;
			this._likeProperties["Username"] = username;	
			this._likeProperties["Rol.Nombre"] = nombre;	
			this._likeProperties["Rol.Apellido"] = apellido;	
		}
	
		public bool Match(Usuario usuario)
		{
			return base.Match(usuario) && CoincideRol(usuario.Rol.GetType().Name);
		}

		public bool CoincideRol(string rolUsuario)
		{
			return (_tipoRol.Equals(string.Empty) || _tipoRol.Equals(rolUsuario));
		}
	}

	#endregion

	#region Administrador

	public class AdministradorLikePredicate : LikePropertyPredicate
	{
		public AdministradorLikePredicate(string nombre, string apellido)
			: base(new Hashtable(2), new Hashtable())
		{
			this._likeProperties["Nombre"] = nombre;
			this._likeProperties["Apellido"] = apellido;
		}
	
		public bool Match(Administrador admin)
		{
			return base.Match(admin);
		}
	}

	#endregion

	#region Rol Generico
	public class RolGenericoLikePredicate : LikePropertyPredicate
	{		
		public RolGenericoLikePredicate(string nombre, string apellido)
			: base(new Hashtable(2), new Hashtable())
		{
			this._likeProperties["Nombre"] = nombre;	
			this._likeProperties["Apellido"] = apellido;
		}
	
		public bool Match(RolGenerico rolGenerico)
		{
			return base.Match(rolGenerico);
		}
	}
	#endregion

	#region Inscripcion

	public class InscripcionesAbiertasPredicate : Predicate
	{
		private string _docenteId;

		public InscripcionesAbiertasPredicate(string docenteId)
		{
			_docenteId = docenteId;
		}

		public bool Match(Inscripcion inscripcion)
		{
			return (inscripcion.Docente.Id.Equals(_docenteId)
					&& (inscripcion.Concurso.Estado.Equals(EstadoConcurso.ABIERTOAINSCRIPCION) ));
		}
	}

	#endregion

	#region Lista Valores

	public class ListaValoresPredicate : Predicate
	{
		private string _idAntecedenteMeta;
		private string _idAtributoMeta;

		public ListaValoresPredicate(string idAntecedenteMetadato, string idAtributoMetadato)
		{
			_idAntecedenteMeta = idAntecedenteMetadato;
			_idAtributoMeta = idAtributoMetadato;
		}

		public bool Match(ItemListaValores itemListaValores)
		{
			return (coincideIdAtributo(itemListaValores) && coincideIdAntecedente(itemListaValores));
		}		

		private bool coincideIdAtributo(ItemListaValores itemListaValores)
		{
			bool coincide = true;
			if (!_idAtributoMeta.Equals(string.Empty))
			{				
				coincide =	(itemListaValores.AtributoMetadato != null) &&				
							itemListaValores.AtributoMetadato.Id.Equals(_idAtributoMeta);
			}
			return coincide;
		}

		private bool coincideIdAntecedente(ItemListaValores itemListaValores)
		{
			bool coincide = true;
			if (!_idAntecedenteMeta.Equals(string.Empty))
			{
				coincide =	(itemListaValores.AntecedenteMetadato != null) &&
					itemListaValores.AntecedenteMetadato.Id.Equals(_idAntecedenteMeta);
			}
			return coincide;					 
		}
	}

	#endregion

	#region Concurso

	public class InscripcionesConcursoPredicate : Predicate
	{
		string _concursoId;
	
		public InscripcionesConcursoPredicate(string concursoId)
		{
			_concursoId = concursoId;
		}

		public bool Match(Inscripcion inscripcion)
		{
			return inscripcion.Concurso.Id.Equals(_concursoId);
		}
	}

	public class GetConcursosLikePredicate : LikePropertyPredicate
	{
		public GetConcursosLikePredicate(string nombre, object fecha, object departamentoId, object areaId)
			: base(new Hashtable(), new Hashtable())
		{
			this._likeProperties["Nombre"] = nombre;
			this._equalProperties["Fecha"] = fecha;
			this._equalProperties["Departamento.Id"] = departamentoId;
			this._equalProperties["Area.Id"] = areaId;
		}

		public bool Match(Concurso concurso)
		{
			return base.Match(concurso);
		}
	}

	public class ConcursoAbiertosByJuradoPredicate : Predicate
	{	
		string _juradoId;

		public ConcursoAbiertosByJuradoPredicate(string juradoId)
		{
			_juradoId = juradoId;
		}

		public bool Match(Concurso concurso)
		{
			if ((concurso.Estado.Equals(EstadoConcurso.ABIERTOAINSCRIPCION)))
			{
				if (concurso.JuradosEnConcurso != null)
				{
					foreach(JuradoEnConcurso juradoEnConcurso in concurso.JuradosEnConcurso)
					{
						if ((juradoEnConcurso.Jurado != null) &&
							juradoEnConcurso.Jurado.Id.Equals(_juradoId))
						{
							return true;
						}
					}
				}
			}
			return false;
		}
	}
	public class ConcursosAbiertosPredicate : Predicate
	{
		public ConcursosAbiertosPredicate()
		{}

		public bool Match(Concurso concurso)
		{
			return concurso.Estado.Equals(EstadoConcurso.ABIERTOAINSCRIPCION);
		}
	}

	#endregion

	#region Jurado

	// Estilo Native Queries...No usadas. (Mayor OO)
	public class GetJuradosPredicate : Predicate
	{
		string _nombre;
		string _apellido;
		string _idInstitucion;

		public GetJuradosPredicate(string nombre, string apellido, string idInstitucion)
		{
			_nombre = nombre;
			_apellido = apellido;
			_idInstitucion = idInstitucion;
		}

		public bool Match(Jurado j)
		{
			// es tru si matchea el nombre o viene string vacio Y
			// matchea el apellido o viene string vacio Y
			// matchea el id institucion o viene nulo
			return	((j.Nombre.IndexOf(_nombre) >= 0) || (_nombre.Equals(string.Empty)))  &&
				((j.Apellido.IndexOf(_apellido) >= 0)  || (_apellido.Equals(string.Empty))) &&
				((j.Institucion.Id == _idInstitucion) || (_idInstitucion == null));
		}
	}


	public class GetJuradoLikePredicate : LikePropertyPredicate
	{
		public GetJuradoLikePredicate(string nombre, string apellido, string idInstitucion)
			: base(new Hashtable(2), new Hashtable(1))
		{
			this._likeProperties["Nombre"] = nombre;
			this._likeProperties["Apellido"] = apellido;
			this._equalProperties["Institucion.Id"] = idInstitucion;
		}
	
		public bool Match(Jurado jurado)
		{
			return base.Match(jurado);
		}
	}


	public class GetAtributoMetadatoLikePredicate : LikePropertyPredicate
	{
		public GetAtributoMetadatoLikePredicate(string nombre, string idTipo)
			: base(new Hashtable(1), new Hashtable(1))
		{
			this._likeProperties["Nombre"] = nombre;
			this._equalProperties["IdTipoDato"] = idTipo;
		}
	
		public bool Match(AtributoMetadato atributoMeta)
		{
			return base.Match(atributoMeta);
		}
	}
	

	#endregion

	#region Jurado En Concurso

	public class GetJuadoEnConcursoByConcurso : Predicate
	{
		string _idConcurso;

		public GetJuadoEnConcursoByConcurso(string concursoId)
		{
			this._idConcurso = concursoId;
		}

		public bool Match(JuradoEnConcurso juradoEnConcurso)
		{
			return (juradoEnConcurso.Concurso != null) &&			
					juradoEnConcurso.Concurso.Id.Equals(_idConcurso);
		}
	}

	public class GetJuadoEnConcurso : Predicate
	{
		string _idConcurso;
		string _idJurado;

		public GetJuadoEnConcurso(string concursoId, string juradoId)
		{
			this._idConcurso = concursoId;
			this._idJurado = juradoId;
		}

		public bool Match(JuradoEnConcurso juradoEnConcurso)
		{
			return (juradoEnConcurso.Concurso != null) &&			
				juradoEnConcurso.Concurso.Id.Equals(_idConcurso) &&
				juradoEnConcurso.Jurado.Id.Equals(_idJurado);
		}
	}

	#endregion

	#region Version

	public class VersionLikePredicate : LikePropertyPredicate 
	{
		public VersionLikePredicate(string nombreDocente)
			:base(new Hashtable(1), new Hashtable())
		{
			this._likeProperties["Nombre"] = nombreDocente;
		}

		public bool Match(VersionCurriculo version)
		{			
			return base.Match(version.Docente);			
		}
	}

	public class VersionByDocenteIdPredicate : Predicate 
	{
		private string _idDocente;
		public VersionByDocenteIdPredicate(string docenteID)			
		{
			_idDocente = docenteID;
		}

		public bool Match(VersionCurriculo version)
		{			
			return ((version.Docente != null) &&
					version.Docente.Id.Equals(_idDocente));
		}
	}	

	#endregion

	#region Calificador Concurso

	public class GetCalificadoresByConcursoPredicate : Predicate
	{
		string _idConcurso;

		public GetCalificadoresByConcursoPredicate(string concursoId)
		{
			this._idConcurso = concursoId;
		}

		public bool Match(CalificadorConcursoCVs calificador)
		{
			if (calificador.JuradosEnConcurso != null)
			{
				// todos los jurados en concurso que tenga el calificador van a pertenecer al mismo concurso
				// por lo tanto me fijo en el primero de la lista si corresponde a un calificador del concurso 
				// solicitado.
				JuradoEnConcurso juradoEnConcurso = calificador.JuradosEnConcurso[0] as JuradoEnConcurso;

				if ((juradoEnConcurso != null) && (juradoEnConcurso.Concurso != null) && (juradoEnConcurso.Concurso.Id.Equals(_idConcurso)))
				{
					return true;
				}				
			}

			return false;
		}
	}

	public class GetCalificadoresByJuradoPredicate : Predicate
	{
		string _juradoId;

		public GetCalificadoresByJuradoPredicate(string juradoId)
		{
			this._juradoId = juradoId;
		}

		public bool Match(CalificadorConcursoCVs calificador)
		{
			if (calificador.JuradosEnConcurso != null)
			{
				foreach (JuradoEnConcurso juradoEnConcurso in calificador.JuradosEnConcurso)
				{
					if ((juradoEnConcurso != null) && (juradoEnConcurso.Jurado != null) && (juradoEnConcurso.Jurado.Id.Equals(_juradoId)))
					{
						return true;
					}					
				}				
			}

			return false;
		}
	}


	public class GetCalificadorByConcursoAndJuradoPredicate : Predicate
	{
		string _idConcurso;
		string _idJurado;

		public GetCalificadorByConcursoAndJuradoPredicate(string concursoId, string juradoId)
		{
			this._idConcurso = concursoId;
			this._idJurado = juradoId;
		}

		private bool PerteneceAConcursoYJuradoBuscados(JuradoEnConcurso juradoEnConcurso)
		{
			return ((juradoEnConcurso != null) 
					&& (juradoEnConcurso.Concurso != null) 
					&& (juradoEnConcurso.Concurso.Id.Equals(_idConcurso))
					&& juradoEnConcurso.Jurado.Id.Equals(_idJurado));
		}

		public bool Match(CalificadorConcursoCVs calificador)
		{
			if (calificador.JuradosEnConcurso != null)
			{
				foreach (JuradoEnConcurso juradoEnConcurso in calificador.JuradosEnConcurso)
				{
					if (PerteneceAConcursoYJuradoBuscados(juradoEnConcurso))
					{
						return true;
					}
				}
			}

			return false;
		}
	}

	#endregion

	#region Antecedentes

	public class AntecedenteByTipoPredicate : Predicate
	{
		string _idTipoAntecedente;

		public AntecedenteByTipoPredicate(string idTipoAntecedente)			
		{
			_idTipoAntecedente = idTipoAntecedente;
		}		

		public bool Match(Antecedente antecedente)
		{			
			return antecedente.IdAntecedenteMetadato.Equals(_idTipoAntecedente);			
		}
	}

	#endregion 	

	#region AdHoc

	public class GetAdHocsPredicate : Predicate
	{
		string _idConcurso;
		string _idAntecedenteMetadato;

		public GetAdHocsPredicate(string idConcurso, string idAntecedenteMetadato)
		{
			_idConcurso = idConcurso;
			_idAntecedenteMetadato = idAntecedenteMetadato;
		}

		public bool Match(AdHoc adHoc)
		{
			return ( adHoc.AntecedenteMetadato.Id.Equals(_idAntecedenteMetadato)
					&& adHoc.Concurso.Id.Equals(_idConcurso));
		}
	}

	public class AdHocAsignadoPredicate : Predicate
	{
		string _idAdHoc;
		
		public AdHocAsignadoPredicate(string idAdHoc)
		{
			_idAdHoc = idAdHoc;
		}

		public bool Match(ValorAdHoc valorAdHoc)
		{
			return valorAdHoc.AdHocAsignado.Id.Equals(_idAdHoc);
		}

	}

	public class ValorAdHocPredicate : Predicate
	{
		string _idConcurso;
		Antecedente _antecedente;
		string _idAdHoc;

		public ValorAdHocPredicate(string idConcurso, Antecedente antecedente)
		{
			_antecedente = antecedente;
			_idConcurso = idConcurso;
			_idAdHoc = string.Empty;
		}

		public ValorAdHocPredicate(string idAdHoc)
		{
			_idAdHoc = idAdHoc;
			_idConcurso = string.Empty;
			_antecedente = null;
		}

		public bool Match(ValorAdHoc valorAdHoc)
		{
			if (_idAdHoc.Equals(string.Empty))
			{
				return ( valorAdHoc.Antecedente.Equals(_antecedente) 
						&& valorAdHoc.AdHocAsignado.Concurso.Id.Equals(_idConcurso));
			}
			else
			{
				return valorAdHoc.AdHocAsignado.Id.Equals(_idAdHoc);
			}
		}
	}

	#endregion

	#region TipoAntecedenteHoja
	public class TipoAntecedenteHojaPredicate : Predicate
	{
		string _antecedenteMetadatoId;
		string _idConcurso;

		public TipoAntecedenteHojaPredicate(string antecedenteMetadatoId, string idConcurso)
		{
			_antecedenteMetadatoId = antecedenteMetadatoId;
			_idConcurso = idConcurso;
		}

		public bool Match(TipoAntecedenteHoja tipoAntecedenteHoja)
		{
			return ( tipoAntecedenteHoja.AntecedenteMetadato.Id.Equals(_antecedenteMetadatoId)
					&& tipoAntecedenteHoja.Concurso.Id.Equals(_idConcurso));
		}
	}
	#endregion

	#region Metrica y Tope (DatosValoracion)
	
	public class DatosValoracionPredicate : Predicate
	{
		string _idConcurso;
		string _idAntecedenteMetadato;

		public DatosValoracionPredicate(string idConcurso, string idAntecedenteMetadato)
		{
			_idConcurso = idConcurso;
			_idAntecedenteMetadato = idAntecedenteMetadato;
		}

		public bool Match(DatosValoracion datosValoracion)
		{
			return (datosValoracion.AntecedenteMetadato.Id.Equals(_idAntecedenteMetadato)
					&& datosValoracion.Concurso.Id.Equals(_idConcurso));
		}
	}

	#endregion

	public class ObjectByIdPredicate : Predicate
	{
		private string _id;
		private Type _tipo;


		public ObjectByIdPredicate(string id, Type tipo)
		{
			this._id = id;
			this._tipo = tipo;
		}

		public bool Match(IObjetoId objeto)
		{
			return objeto.Id.Equals(this._id) && objeto.GetType().Equals(this._tipo);
		}
	}

	public class LikePropertyPredicate : Predicate
	{
		protected Hashtable _likeProperties;
		protected Hashtable _equalProperties;

		public LikePropertyPredicate(Hashtable likeProperties, Hashtable equalsProperties)
		{
			_likeProperties = likeProperties;
			_equalProperties = equalsProperties;
		}	


		public bool Match(object obj)
		{
			return this.MatchProperties(obj);
		}


		protected bool MatchProperties(object obj)
		{			
			return (MatchLikeProperties(obj) && MatchEqualsProperties(obj));
		}


		private bool MatchLikeProperties(object obj)
		{
			bool returnValue = true;

			// recorro todas las properties con las que quiere hacer el like
			// y los valores con los que deben matchear.
			foreach (DictionaryEntry entry in _likeProperties)
			{					
				// obtengo el valor de la property del objeto de la base en "propValue"
				object propValue = GetPropertyValue(obj, entry.Key.ToString());

				if ((propValue != null) && EntradaNoVacia(entry.Value))
				{
					returnValue = ((propValue.ToString().ToLower().IndexOf(entry.Value.ToString().ToLower()) >=0) && returnValue);
				}
				else
				{
					// Si el objeto de la base no tiene ningun valor hago q no matchee con nada.
					returnValue = !EntradaNoVacia(entry.Value) && returnValue;
				}
			}

			return returnValue;
		}


		private bool EntradaNoVacia(object valor)
		{
			return (valor != null) && (valor.ToString() != string.Empty);
		}


		private bool MatchEqualsProperties(object obj)
		{
			bool returnValue = true;

			// recorro todas las properties con las que quiere hacer el like
			// y los valores con los que deben matchear.
			foreach (DictionaryEntry entry in _equalProperties)
			{						
				object propValue = GetPropertyValue(obj, entry.Key.ToString());
			
				if ((propValue != null) && (EntradaNoVacia(entry.Value)))
				{
					returnValue = (propValue.Equals(entry.Value) && returnValue);
				}
				else
				{
					returnValue = !EntradaNoVacia(entry.Value) && returnValue;
				}
			}

			return returnValue;
		}


		private bool isValidEntry(DictionaryEntry entry)
		{
			return (entry.Key.GetType().Equals(typeof(string)) &&
				!entry.Value.GetType().Equals(typeof(string)));
		}


		private object GetPropertyValue(object obj, string propertyPath)
		{
			string[] pathComponents = null;
			// Separo a la property en los distintos objetos que la pueden componer. 
			// Ejemplo Jurado.Institucion.Id
			pathComponents = propertyPath.Split('.');
		
			int componentNumber = 0;
			object property = null;

			while (componentNumber < pathComponents.Length)
			{
				property = obj.GetType().GetProperty(pathComponents[componentNumber]).GetValue(obj,null);
				if (property == null) break; // si no tiene valor la property => sale del ciclo.

				componentNumber++;				
				obj = property;
			}
		
			return property;
		}
	}
	

	#endregion Predicates
}

